package ru.zombator.taskman.server.query;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import ru.zombator.taskman.core.dbclient.DbException;
import ru.zombator.taskman.core.query.IPacket;
import ru.zombator.taskman.core.query.IResponderSvc;
import ru.zombator.taskman.core.query.IResponderCli;
import ru.zombator.taskman.core.query.ITypedPacket;
import ru.zombator.taskman.core.query.LogHandler;
import ru.zombator.taskman.core.query.TypedPacket;
import ru.zombator.taskman.core.query.payload.ErrorResponse;

/**
 * Ответчик единообразно отвечает на запросы от пользователей.
 * <p>
 * Сервера делегируют ответчику выполнение того, чего просят от них пользователи
 * :)
 * 
 * @author nvamelichev
 * 
 */
public class LocalResponder implements IResponderCli, IResponderSvc {
	private static final long serialVersionUID = 1L;

	private Map<Class<?>, IRequestHandler> handlers = new HashMap<Class<?>, IRequestHandler>();
	private Logger log = new Logger();

	@Override
	public IPacket getResponse(IPacket request) {
		try {
			ITypedPacket tp = new TypedPacket(request);
			Object reqObj = tp.asObject();
			IRequestHandler handler = handlers.get(reqObj.getClass());
			if (handler != null) {
				try {
					return new TypedPacket(handler.getResponse(reqObj, log))
							.asUntyped();
				} catch (DbException e) {
					log.log("Ошибка при обработке запроса [%s]: %s.", reqObj
							.getClass().getSimpleName(), e.getMessage());
					return new TypedPacket(new ErrorResponse(e.getMessage()))
							.asUntyped();
				}
			} else {
				log.log("Передан неизвестный тип запроса: [%s]", reqObj
						.getClass().getSimpleName());
				return new TypedPacket(new ErrorResponse(
						"Неизвестный вид запроса.")).asUntyped();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Устанавливает обработчик для данного вида запросов
	 * 
	 * @param requestClass
	 *            вид запросов
	 * @param handler
	 *            обработчик
	 */
	public void setHandler(Class<?> requestClass, IRequestHandler handler) {
		handlers.put(requestClass, handler);
	}

	/**
	 * Снимает обработчик для данного вида запросов
	 * 
	 * @param requestClass
	 *            вид запросов
	 */
	public void clearHandler(Class<?> requestClass) {
		handlers.remove(requestClass);
	}

	@Override
	public void dispose() {
	}

	@Override
	public void addLogHandler(LogHandler handler) {
		log.addHandler(handler);
	}

	@Override
	public void removeLogHandler(LogHandler handler) {
		log.removeHandler(handler);
	}
}
